{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"../common/rfsoc_book_banner.jpg\" alt=\"University of Strathclyde\" align=\"left\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-block\" style=\"background-color: #c7b8d6; padding: 10px\">\n",
    "    <p style=\"color: #222222\">\n",
    "        <b>Note:</b>\n",
    "        <br>\n",
    "        This Jupyter notebook uses hardware features of the Zynq UltraScale+ RFSoC device. Therefore, the notebook cells will only execute successfully on an RFSoC platform.\n",
    "    </p>\n",
    "</div>\n",
    "\n",
    "# Notebook Set I\n",
    "\n",
    "---\n",
    "\n",
    "## 03 - RFSoC OFDM Transceiver\n",
    "This notebook demonstrates the implementation of an Orthogonal Frequency Division Multiplexing (OFDM) transceiver on RFSoC. PYNQ is used to control the underlying modulation scheme of the OFDM sub-carriers and for visualisation of data at various stages in the transmit/receive chain, such as the received constellations.\n",
    "\n",
    "## Table of Contents\n",
    "* [1. Introduction](#introduction)\n",
    "    * [1.1 Hardware Setup](#hardware-setup)\n",
    "    * [1.2 Software Setup](#software-setup)\n",
    "* [2. OFDM Transmitter](#ofdm-transmitter)\n",
    "* [3. OFDM Receiver](#ofdm-receiver)\n",
    "* [4. Conclusion](#conclusion)\n",
    "\n",
    "## Revision\n",
    "* **v1.0** | 05/01/23 | *First Revision*\n",
    "* **v1.1** | 19/05/23 | *Fix header numbering*\n",
    "* **v1.2** | 19/05/23 | *Add ZCU216 and ZCU208*\n",
    "\n",
    "---\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Introduction <a class=\"anchor\" id=\"introduction\"></a>\n",
    "The demonstrator is a complete OFDM transceiver. This notebook will explain each stage of the system with a combination of text, diagrams and live data capture. Figure 1 below provides an overview of the system.\n",
    "\n",
    "<figure>\n",
    "<img src=\"./images/ofdm_architecture.png\" height='75%' width='75%'/>\n",
    "    <figcaption><b>Figure 1: OFDM demonstrator system overview.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "The OFDM system starts with generation of random data symbols from 1 of 10 possible modulation schemes (BPSK to 1024 QAM), based on input provided from PYNQ. In accordance with the procedure used in the IEEE 802.11a/g standard, the symbols are grouped into blocks of 48 for mapping to sub-carriers. The OFDM symbol consists of 48 data sub-carriers, 4 pilot sub-carriers and 12 null sub-carriers (including DC). The final OFDM symbol is created by performing a 64 point IFFT and adding a 16 sample Cyclic Prefix (CP). The transmitted signal consists of a continuous stream of OFDM symbols. At the very beginning of the data stream, the L-STF and L-LTF training symbols from the IEEE 802.11a/g standard are transmitted, to aid synchronisation and channel estimation tasks in the receiver. \n",
    "\n",
    "In the receiver, timing and frequency synchronisation are performed to acquire symbol timing and correct for any frequency offsets. Once timing is achieved, the FFT is performed to recover the underlying data symbols in each OFDM symbol. The L-LTF symbols are used to estimate the channel frequency response at each sub-carrier position, which subsequently allows the data to be equalised. Finally, the pilot symbols are used to correct for residual phase errors in the phase tracking stage. The recovered symbols are then passed into the PS for visualisation in PYNQ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "### 1.1. Hardware Setup <a class=\"anchor\" id=\"zcu208_and_zcu216\"></a>\n",
    "The ZCU208 development boards require the SMA and clock connections to be setup correctly. We will begin with connecting the clocks from the Clk104 card to the development board. Then connect the ADC and DAC to the HW_XM_655 card's RF baluns.\n",
    "\n",
    "Before you begin with the setup below, ensure that the Clk104 card and HW_XM_655 card is securely connected to the ZCU208 development board.\n",
    "\n",
    "#### 1.1.1. CLK104 Setup <a class=\"anchor\" id=\"clk104_setup\"></a>\n",
    "On the Clk104 board, make the following connections as shown in [Figure 2](#fig-2).\n",
    "\n",
    "<a class=\"anchor\" id=\"fig-2\"></a>\n",
    "<figure>\n",
    "<img src='images/clk104_setup.jpg' height='50%' width='50%'/>\n",
    "    <figcaption><b>Figure 2: Setup of the clk104 add-on board on the ZCU208.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "Ensure that the clocks above are connected as follows:\n",
    "* DAC_229_CLK to DAC_RFCLK_B (P & N).\n",
    "* ADC_225_CLK to ADC_RFCLK_B (P & N).\n",
    "\n",
    "If you do not make the correct connection, the demonstration will not operate correctly.\n",
    "\n",
    "#### 1.1.2. ADC Setup <a class=\"anchor\" id=\"adc_setup\"></a>\n",
    "The next step is to connect the ADC to the RF Balun on the HW_XM_655 card. See the image below in [Figure 3](#fig-3) on how to make this connection successfully. You will need the rectangle connector that contains a strip of wires with SMAs attached to make this connection. This connector is known as the Carlisle SMA 8 Cable Assemblies in the kit contents page supplied with your development board.\n",
    "\n",
    "<a class=\"anchor\" id=\"fig-3\"></a>\n",
    "<figure>\n",
    "<img src='images/zcu2xx_adc_setup.jpg' height='50%' width='50%'/>\n",
    "    <figcaption><b>Figure 3: Setting-up the ADC on the HW_XM_655 card.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "Ensure that the ADC connections are setup as follows:\n",
    "* JHC5 P0_255 to J18\n",
    "* JHC5 N01_255 to J16\n",
    "\n",
    "This step is a little difficult as there are many small wires. Please take your time setting up the ADC to prevent errors.\n",
    "\n",
    "#### 1.1.3. DAC Setup <a class=\"anchor\" id=\"dac_setup\"></a>\n",
    "The DAC is connected to the RF Balun on the HW_XM_655 card using the connections shown in [Figure 4](#fig-4) below.\n",
    "\n",
    "<a class=\"anchor\" id=\"fig-4\"></a>\n",
    "<figure>\n",
    "<img src='images/zcu2xx_dac_setup.jpg' height='50%' width='50%'/>\n",
    "    <figcaption><b>Figure 4: Setting-up the DAC on the HW_XM_655 card.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "Ensure that the DAC connections are setup as follows:\n",
    "* JHC3 P0_230 to J39\n",
    "* JHC3 N0_230 to J37\n",
    "\n",
    "Take your time with this step to prevent errors during the demonstration.\n",
    "\n",
    "#### 1.1.4. Loopback Setup <a class=\"anchor\" id=\"loopback_setup\"></a>\n",
    "We can now connect each RF Balun together using an SMA cable contained in your ZCU208 box. The image below in [Figure 5](#fig-5) shows how to make this connection.\n",
    "\n",
    "<a class=\"anchor\" id=\"fig-5\"></a>\n",
    "<figure>\n",
    "<img src='images/zcu2xx_sma_conn.jpg' height='50%' width='50%'/>\n",
    "    <figcaption><b>Figure 5: Connecting the ADC to the DAC in loopback mode on the HW_XM_655 card.</b></figcaption>\n",
    "</figure>\n",
    " \n",
    "The connection shown in the image above is the following:\n",
    "* J17 (LFB_ADC_02) to J38 (LFB_DAC_01)\n",
    "\n",
    "Your ZCU208 development board is now ready for the demonstration."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-box alert-danger\">\n",
    "<b>Caution:</b>\n",
    "    In this demonstration, we generate signals using the RFSoC development board. Your device should be setup in loopback mode. You should understand that the RFSoC platform can also transmit RF signals wirelessly. Remember that unlicensed wireless transmission of RF signals may be illegal in your geographical location. Radio signals may also interfere with nearby devices, such as pacemakers and emergency radio equipment. Note that it is also illegal to intercept and decode particular RF signals. If you are unsure, please seek professional support.\n",
    "</div>\n",
    "\n",
    "### 1.2. Software Setup\n",
    "The setup for the OFDM demonstration system is nearly complete. The majority of the libraries used by the demonstrator design are contained inside the RFSoC-OFDM software package. We only need to run a few code cells to initialise the environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from rfsoc_ofdm.overlay import Overlay\n",
    "import ipywidgets as ipw\n",
    "\n",
    "ofdm_hw = Overlay()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. OFDM Transmitter <a class=\"anchor\" id=\"ofdm-transmitter\"></a>\n",
    "There are a total of 10 modulation schemes available to be transmitted. These are generated on the programmable logic and can be chosen between by updating the *ofdm_tx IP core's* **mod** register with a value from 0-9 over AXI4-Lite. [Figure 6](fig-6) illustrates the IP core as a simplified block diagram.\n",
    "\n",
    "<figure>\n",
    "<img src=\"./images/ofdm_modulation_selector.png\" height='35%' width='35%'/>\n",
    "    <figcaption><b>Figure 6: Symbol generation block diagram.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "This drop down widget sends the value associated with each modulation scheme to the ofdm_tx core. Run the cell below to use it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ofdm_hw.ofdm_transmitter.modulation_dropdown.get_widget()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The output of the symbol generation block has been tapped off, allowing for the live symbols to be visualised in Jupyter Lab. Run the cell below and hit play on the chart to inspect the symbols generated on the programmable logic."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ipw.VBox([ofdm_hw.inspectors['transmitter'].time_plot(),\n",
    "          ofdm_hw.inspectors['transmitter'].plot_control()])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. OFDM Receiver\n",
    "Run the cell below to see the output of the OFDM receiver displayed as a constellation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ipw.VBox([ofdm_hw.inspectors['constellation'].constellation_plot(),\n",
    "          ofdm_hw.inspectors['constellation'].plot_control()])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Try changing the modulation scheme using the code cell that was ran earlier. You should be able to visualise the modulation schemes in the plot above."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Conclusion\n",
    "This notebook has demonstrated a live OFDM transceiver operating on an RFSoC. It has been shown how PYNQ can be used to interact with various parts of the hardware design, offering control of the system and visualisation of data. \n",
    "\n",
    "* The various components comprising the OFDM transmitter and receiver have been introduced at a high level. \n",
    "    * Modulation symbols were inspected.\n",
    "    * The received and sychronised constellation were plotted.\n",
    "* Interacted with a real-time RF system.\n",
    "    * Changed modulation scheme.\n",
    "    \n",
    "Congratulations! You have completed all practical exercises in the RFSoC Book."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "[⬅️ Previous Notebook](02_ofdm_python_transceiver.ipynb)\n",
    "\n",
    "Copyright © 2023 Strathclyde Academic Media\n",
    "\n",
    "---\n",
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
